// /////////////////////////////////////////////////////////////////////////////
//
// Name:            AICore.h
// Author:          Michael Bartsch
//
// Desc :           The interface for the A* Pather system.
//
// License:         Copyright (C) 2008-2009 Michael Bartsch
//
//                  This program is free software: you can redistribute it
//                  and/or modify it under the terms of the GNU General Public
//                  License as published by the Free Software Foundation,
//                  either version 3 of the License, or (at your option) any
//                  later version.
//
//                  This program is distributed in the hope that it will be
//                  useful, but WITHOUT ANY WARRANTY; without even the implied
//                  warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
//                  PURPOSE. See the GNU General Public License for more
//                  details.
//
//                  You should have received a copy of the GNU General Public
//                  License along with this program. If not, see
//                  <http://www.gnu.org/licenses/>.
//
// /////////////////////////////////////////////////////////////////////////////

#ifndef __C_AICORE_H_INCLUDED__
#define __C_AICORE_H_INCLUDED__

// Include required header file(s).
#include "Communicator.h"

#include <vector>
#include <algorithm>

// Declare namespaces.
using namespace std;

// Forward Declarations.
class CAStarNode;
class CAICore;


// Enumerations.
//! States for the A* Nodes.
enum AStarNodeStates
{
   ASN_Walkable = 0,
   ASN_Unwalkable,
   ASN_Unknown
};

//! States of the AI Core for the path calculation.
enum AICoreStates
{
   ASP_Found = 1,
   ASP_NoPath
};


// The CAStarNode class.
//! Abstract class that represents a cell in the map of the AICore class.
class CAStarNode
{
public:

    //! Constructor
    CAStarNode();
    //! Deconstructor
    ~CAStarNode();

    CAStarNode *parent;
    int x, y;
    short int state;
    int G, F, H;
    bool onOpenList, onClosedList;
};


// Sorting function.
//! Sorts a list based upon the F value of a node.
bool sortListF(CAStarNode *i, CAStarNode *j);


// The CAICore class.
//! Main entry point to the PC-based control of the Aia.
//! The Aia can be directly controlled through this class.
//!
//! @note A singleton metatable with the same functionalities as the
//! CAICore class can be accessed through the Lua Scripting
//! language. The functions of this metatable can be accessed with
//! AICore:<function> (notice the colon!). If the end-user
//! does not wish to use the AICore metatable in Lua he/she
//! can decide to use ai<function>.
//!
//! @see AIScript.cpp AIScript.h
class CAICore
{
public:

    //! Constructor
    CAICore();
    //! Deconstructor
    ~CAICore();

    //! Returns an instance of the singleton of CAICore
    static CAICore* Instance();

    //! Updates the AI Core.
    //! @see lua_ai_update
    void update();

    //! Calculates a path to the target location using the A* algorithm.
    //! @return result of execution
    //! @see lua_ai_calculatePath
    //! @see AICoreStates
    int calculatePath();
    //! Checks the environment for possible new data.
    //! @see lua_ai_checkEnvironment
    void checkEnvironment();

    // Get functions.
    //! Returns the pointer to the given node.
    //! @param x the x-coordinate of the node
    //! @param y the y-coordinate of the node
    CAStarNode* getNode(int x, int y);

    //! Returns the x-coordinate of the starting position.
    //! @return x-coordinate
    //! @see lua_ai_getStartX
    int getStartX();
    //! Returns the y-coordinate of the starting position.
    //! @return y-coordinate
    //! @see lua_ai_getStartY
    int getStartY();
    //! Returns the x-coordinate of the target position.
    //! @return x-coordinate
    //! @see lua_ai_getTargetX
    int getTargetX();
    //! Returns the y-coordinate of the target position.
    //! @return y-coordinate
    //! @see lua_ai_getTargetY
    int getTargetY();
    //! Returns the y-coordinate of the next cell.
    //! @return y-coordinate
    //! @see lua_ai_getNextX
    int getNextX();
    //! Returns the x-coordinate of the next cell.
    //! @return x-coordinate
    //! @see lua_ai_getNextY
    int getNextY();

    //! Returns the virtual rotation of the agent.
    //! @return the virtual rotation
    //! @see lua_ai_getRotation
    int getRotation();

    //! Does the agent have a target?
    //!
    //! @note If the target isn't enabled it doesn't mean that the agent is idle.
    //! In case a colour target has been specified the agent will examine the
    //! environment for that colour.
    //! @see lua_ai_getIsTarget
    bool getIsTarget();

    //! Gets the state of the agent.
    //! @return the state of the agent
    //! @see lua_ai_getAgentState
    //! @see setAgentState
    int getAgentState();

    //! Gets the waiting state of the AI Core.
    //! @return is the AI Core waiting?
    //! @see lua_ai_getIsWaiting
    //! @see setIsWaiting
    bool getIsWaiting();

    // Set functions.
    //! Sets the start location.
    //! @param x the x-coordinate
    //! @param y the y-coordinate
    //! @see lua_ai_setStartLocation
    void setStartLocation(int x, int y);
    //! Sets the x-coordinate of the start location.
    //! @param x the x-coordinate
    //! @see lua_ai_setStartX
    void setStartX(int x);
    //! Sets the y-coordinate of the start location.
    //! @param y the y-coordinate
    //! @see lua_ai_setStartY
    void setStartY(int y);

    //! Sets the target location.
    //! @param x the x-coordinate
    //! @param y the y-coordinate
    //! @see lua_ai_setTargetX
    void setTargetLocation(int x, int y);
    //! Sets the x-coordinate of the target location.
    //! @param x the x-coordinate
    //! @see lua_ai_setTargetX
    void setTargetX(int x);
    //! Sets the y-coordinate of the target location.
    //! @param y the y-coordinate
    //! @see lua_ai_setTargetY
    void setTargetY(int y);

    //! Sets the virtual rotation of the agent.
    //! @note executing this code doesn't result in a real life rotation of the
    //! agent. In case you want a real life rotation of the agent, you should
    //! execute the lua_ai_serialWrtie function.
    //! @param value the new rotation value
    //! @see lua_ai_setRotation
    void setRotation(int value);

    //! Sets the state of the selected node.
    //! @param x the x-coordinate of the node
    //! @param y the y-coordinate of the node
    //! @param state the state the node will be in
    //! @see lua_ai_setNodeState
    void setNodeState(int x, int y, AStarNodeStates state);

    //! Sets the states of all nodes up to the given distance.
    //! @param distance distance to set
    void setNodesSonar(int distance);

    //! Activate the given target.
    //! @param value activation state
    //! @see lua_ai_setIsTarget
    void setIsTarget(bool value);

    //! Sets the state of the agent.
    //! The Aia can be in two states:
    //! - Off (0)
    //! - Target (1): finds the shortest path to the given location target
    //!
    //! @note If a colour target has been set, the location target will be overridden.
    //! The original plan was to have either a location target or a colour target. This,
    //! however, required the implementation of a discovery mode. Due to time constraints
    //! this was impossible. You're encouraged, though, to implement it yourself. Happy Hacking! ;)
    //!
    //! @param value state the Aia is in
    //! @see lua_ai_setAgentState
    void setAgentState(int value);

    //! Sets the waiting state of the AI Core
    //! @param value waiting state
    //! @see lua_ai_setIsWaiting
    void setIsWaiting(bool value);

    //! Resets the node map.
    //! @see lua_ai_resetMap
    void resetMap();

private:

    // CAICore singleton.
	static CAICore *pInstance;

    // Variables.
    int startX, startY;
	int targetX, targetY;
	int pathLength;
	int rotation;
	int agentState;

	bool isPathFound;
	bool isTarget;
	bool isWaiting;

	vector<CAStarNode*> openList;
	vector<CAStarNode*>::iterator openListIt;
	vector<CAStarNode*> pathList;

	CAStarNode* currentNode;
	CAStarNode* nextNode;
	CAStarNode* nodeMap;
};

#endif

